<?php
/**
 * @author 	Vu Nhat Lam
 * 			Mail: lamvnd@gmail.com
 * 			Mobile: 0984 52 62 68
 * @version 1.0.0
 */
// ####################### SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~E_NOTICE);
@ini_set('zlib.output_compression', 'Off');
if (@ini_get('output_handler') == 'ob_gzhandler' AND @ob_get_length() !== false)
{
	@ob_end_clean();
	header('Content-Encoding:');
}
@set_time_limit(0);

// #################### DEFINE IMPORTANT CONSTANTS #######################
define('VB_AREA', 'Forum');
define('THIS_SCRIPT', 'bttracker');
define('LOCATION_BYPASS', 1);
define('NOPMPOPUP', 1);
define('NOHEADER', 1);
define('NOZIP', 1);

// ########################## REQUIRE BACK-END ############################
define('CWD', (($getcwd = getcwd()) ? $getcwd : '.'));
require_once(CWD . '/includes/init.php');

// #######################################################################
// ######################### START MAIN SCRIPT ###########################
// #######################################################################
// *****************************************************************************
// Start receive and check main data from peer
foreach (array('passkey', 'info_hash', 'peer_id') AS $key)
{
	if (isset($_GET[$key]))
	{
		$$key = $_GET[$key];
	}
	else
	{
		errorexit("Missing key: $key !");
	}
}

if (strlen($passkey) != 32)
{
	errorexit("Invalid passkey !");
}

foreach (array('info_hash', 'peer_id') AS $key)
{
	if (strlen($$key) != 20)
	{
		errorexit("Invalid parameter: $key !");
	}
}

foreach (array('port', 'downloaded', 'uploaded', 'left') AS $key)
{
	if (isset($_GET[$key]))
	{
		$$key = intval($_GET[$key]);
	} else
	{
		errorexit("Missing key: $key !");
	}
}

if (!$port || $port > 0xffff)
{
	errorexit("Invalid port !");
}

$agent 	   = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : getenv('HTTP_USER_AGENT');
$updateset =  $events_ary = array();

preg_match_all('/event=([^&]*)/i', $_SERVER['QUERY_STRING'], $matches);
if (sizeof($matches[1]))
{
	$events_ary = $matches[1];
}

$compact 	= isset($_GET['compact']) ? 1 : 0;
$no_peer_id = isset($_GET['no_peer_id']) ? 1 : 0;
$rsize 		= 50;

foreach(array('num want', 'numwant', 'num_want') AS $key)
{
	if (isset($_GET[$$key]))
	{
		$rsize = intval($_GET[$key]);
		break;
	}
}
// end receive and check main data from peer
// *****************************************************************************

// *****************************************************************************
// Start check bad clients
$bad_agents_arr = array('Gecko', 'Opera', 'MSIE', 'Links', 'Lynx', 'Mozilla', '0P3R4H');

for ($i = 0; $i < sizeof($bad_agents_arr); $i++)
{
	if (strpos($agent, $bad_agents_arr[$i]) !== false)
	{
		errorexit("Invalid client !");
	}
}

if (strpos($peer_id, 'Torrent/3') && $agent == '0')
{
	errorexit("Invalid client !");
}

if(substr($peer_id, 0, 4) == 'exbc'
	|| substr($peer_id, 0, 3) == '-BC'
	|| substr($peer_id, 1, 2) == 'TS'
	|| substr($peer_id,-4) == 'UDP0'
	|| substr($peer_id, 0, 3) == '-FG')
{
	errorexit("Invalid client !");
}

if(substr($peer_id, 0, 1) == 'A')
{
	if(substr($peer_id, 1, 3) < 300)
	{
		errorexit("Please update or change your torrent-client !");
	}
}

// start anti trackerpro (cheaters)
if ($_SERVER['HTTP_ACCEPT_ENCODING'] == 'identity'
	&& substr($peer_id, 0, 6) == 'M4-1-3')
{
	errorexit("Invalid client !");
}
// end anti trackerpro (cheaters)
// end check bad clients
// *****************************************************************************

// *****************************************************************************
// Start Tracker loger
$db->hide_errors(); // hide error

// start select data for user
$user = $db->query_first_slave("
	SELECT userid, username, usergroupid, seedbonus
	FROM `" . TABLE_PREFIX . "user` AS user
	WHERE passkey = '" . $db->escape_string($passkey) . "'
");

if (!$user)
{
	errorexit("Unknown passkey. Please redownload torrent from tracker !");
}
// end select userdata for user

// start select data for torrent
$torrent = $db->query_first_slave("
	SELECT torrentid, seeders + leechers AS numpeers,
		size, halfleech, freeleech, doubleseed
	FROM " . TABLE_PREFIX . "torrent
	WHERE " . hash_where('info_hash', $info_hash)
);

if (!$torrent)
{
	errorexit("Torrent not registered with this tracker !");
}
// end select data for torrent

$fields = 'userid, peer_id, `left`, ip, port, uploaded, downloaded, updated';

if ($torrent['numpeers'])
{
	$limit = ($torrent['numpeers'] > $rsize ? ' LIMIT ' . $rsize : '');

	$result = $db->query_read_slave("
		SELECT $fields
		FROM " . TABLE_PREFIX . "torrentpeers
		WHERE torrentid = " . $torrent['torrentid'] . "
		$limit
	");

	if (empty($result))
	{
		errorexit('Peer select error !');
	}

	$resp = 'd' . benc_str('interval') . 'i' . $vbulletin->options['torrent_interval'] . 'e' . benc_str('min interval') . 'i' . $vbulletin->options['torrent_min_interval'] . (!$compact ? 'e' . benc_str('peers') . 'l' : 'e5:peers');
	$peer = array();
	$peer_num = 0;

	while ($row = $db->fetch_array($result))
	{
		$row['peer_id'] = str_pad($row['peer_id'], 20);
		$peer_id_replaced = str_replace(' ', '', $row['peer_id']);
		if ($row['peer_id'] == $peer_id || $peer_id_replaced == $peer_id)
		{
			$self = $row;
			continue;
		}
		if(!$compact)
		{
			$resp .= 'd' . benc_str('ip') . benc_str($row['ip']);
			if (!$no_peer_id)
			{
				$resp .= benc_str('peer id') . benc_str($row['peer_id']);
			}
			$resp .= benc_str('port') . 'i' . $row['port'] . 'ee';
		}
		else
		{
			$peer_ip = explode('.', $row['ip']);
			$peer_ip = pack('C*', $peer_ip[0], $peer_ip[1], $peer_ip[2], $peer_ip[3]);
			$peer_port = pack('n*', intval($row['port']));
			$time = intval((TIMENOW % 7680) / 60);
			if(!$left)
			{
				$time += 128;
			}
			$time = pack('C', $time);
			$peer[] = $time . $peer_ip . $peer_port;
			$peer_num++;
		}
	}

	$db->free_result($result);

	if (!$compact)
	{
		$resp .= 'ee';
	}
	else
	{
		$o = '';
		for($i = 0; $i < $peer_num; $i++)
		{
			$o .= substr($peer[$i], 1, 6);
		}
		$resp .= benc_str($o) . 'e';
	}
}
else
{
	$resp = 'd' . benc_str('interval') . 'i' . $vbulletin->options['torrent_interval'] . 'e' . benc_str('min interval') . 'i' . $vbulletin->options['torrent_min_interval'] . (!$compact ? 'e' . benc_str('peers') . 'l' : 'e5:peers0:e');
}

$selfwhere = 'torrentid = ' . $torrent['torrentid'] . ' AND ' . hash_where('peer_id', $peer_id);

if (!isset($self))
{
	$result = $db->query_first_slave("
		SELECT $fields
		FROM " . TABLE_PREFIX . "torrentpeers
		WHERE $selfwhere
	");

	if (!empty($result)) {$self = $result;}
}

if (in_array('completed', $events_ary))
{
	$updateset[] = 'completed = completed + 1';
	$db->query_write("
		INSERT IGNORE " . TABLE_PREFIX . "torrentcomplete
		(torrentid, userid, username, dateline)
		VALUES
		({$torrent['torrentid']}, {$user['userid']}, '".$db->escape_string($user['username'])."', ".TIMENOW.")
	");
}

// start user not in peers table, it's first connect. let's insert data
if (!isset($self))
{
	// start insert data into peers table
	$db->query_write("
		INSERT INTO " . TABLE_PREFIX . "torrentpeers
		(torrentid, userid, username, peer_id, ip, port, uploaded, downloaded, `left`, started, updated, useragent)
		VALUES
		({$torrent['torrentid']}, {$user['userid']}, '".$db->escape_string($user['username'])."', '".$db->escape_string($peer_id)."', '".$vbulletin->input->fetch_alt_ip()."', $port, $uploaded, $downloaded, $left, ".TIMENOW.", ".TIMENOW.", '".$db->escape_string($agent)."')
	");

	if ($db->errno()) errorexit('Insert peers error !');

	if (!$left)
	{
		$updateset[] = 'seeders = seeders + 1';
	}
	else
	{
		$updateset[] = 'leechers = leechers + 1';
	}
	// end insert data into peers table
}
// end user not in peers table, it's first connect. let's insert data

// start user already in peers table, it's first connect. let's update data
else
{
	$upthis   = max(0, $uploaded - $self['uploaded']);
	$downthis = max(0, $downloaded - $self['downloaded']);

	if ($torrent['doubleseed'])
	{
		$user_uploaded = $upthis * 2;
	}
	else
	{
		$user_uploaded = $upthis;
	}

	if ($user['usergroupid'] == 12)
	{// Free leech if is V.I.P group
		$torrent['freeleech'] = true;
	}

	if ($torrent['freeleech'])
	{
		$user_downloaded = 0;
	}
	elseif ($torrent['halfleech'])
	{
		$user_downloaded = intval($downthis / 2);
	}
	else
	{
		$user_downloaded = $downthis;
	}

	$current_seed_time = 0;
	if (!$left && $self['updated'] < TIMENOW)
	{
		$current_seed_time = ((TIMENOW - $self['updated']) / 3600) * ($torrent['size'] / 1073741824) / 10;
	}

	if ($user_uploaded || $user_downloaded || $current_seed_time)
	{
		$db->query_write("
			UPDATE `" . TABLE_PREFIX . "user` SET
			uploaded = uploaded + $user_uploaded,
			downloaded = downloaded + $user_downloaded,
			seedbonus = seedbonus + $current_seed_time
			WHERE userid = {$user['userid']}
		");
	}

	if (in_array('stopped', $events_ary))
	{
		$db->query_write("
			DELETE FROM " . TABLE_PREFIX . "torrentpeers WHERE $selfwhere
		");

		if (!$self['left'])
		{
			$updateset[] = 'seeders = IF(seeders > 0, seeders - 1, 0)';
		}
		else
		{
			$updateset[] = 'leechers = IF(leechers > 0, leechers - 1, 0)';
		}
 	}
	else
	{
		$secs = TIMENOW - $self['updated'];
		// we calculate upload speed for last session
		$uprate = ($secs ? round($upthis / $secs) : 0);
		// we calculate download speed for last session
		$downrate = ($left ? ($secs ? round($downthis / $secs) : 0) : 0);

		$db->query_write("
			UPDATE " . TABLE_PREFIX . "torrentpeers SET
			uploaded = $uploaded,
			upspeed = $uprate,
			downloaded = $downloaded,
			downspeed = $downrate,
			port = $port,
			updated = " . TIMENOW . ",
			`left` = $left
			WHERE $selfwhere
		");

		if (mysql_affected_rows() && $self['left'] != $left && !$left)
		{
			$updateset[] = 'seeders = seeders + 1';
			$updateset[] = 'leechers = IF(leechers > 0, leechers - 1, 0)';
		}
	}
}
//end user already in peers table, it's first connect. let's update data

if (sizeof($updateset))
{
	$db->query_write("
		UPDATE " . TABLE_PREFIX . "torrent SET
		" . implode(',', $updateset) . "
		WHERE torrentid = {$torrent['torrentid']}
	");
}

$db->show_errors();

benc_resp_raw($resp);
